﻿//此类是药剂柜通讯的基础类库
//2017年9月30日09:31:04 顾世豪

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CabinetComTest
{
    /// <summary>
    /// 药剂柜状态类
    /// </summary>
    public class CabinetStatus
    {
        /// <summary>
        /// 温度
        /// </summary>
        public double Tem { get; set; }
        /// <summary>
        /// 湿度
        /// </summary>
        public double Hum { get; set; }
        /// <summary>
        /// 风机是否开启
        /// </summary>
        public bool FanOn { get; set; }
        /// <summary>
        /// 照明灯是否亮
        /// </summary>
        public bool LightOn { get; set; }
        /// <summary>
        /// 电锁是否锁上
        /// </summary>
        public bool LockIsLock { get; set; }
        /// <summary>
        /// 门是否关上
        /// </summary>
        public bool DoorIsClose { get; set; }
        /// <summary>
        /// 运行状态是否正常
        /// </summary>
        public bool RunLigthStatus { get; set; }
        /// <summary>
        /// 通信状态是否正常
        /// </summary>
        public bool SignalLightStatus { get; set; }
        /// <summary>
        /// 滤芯寿命是否正常
        /// </summary>
        public bool FilterLifeLightStatus { get; set; }
        /// <summary>
        /// 异常灯是否亮
        /// </summary>
        public bool AbnormalLightStatus { get; set; }
    }

    /// <summary>
    /// 药剂柜类
    /// </summary>
    public static class Cabinet
    {
        //通讯串口
        private static SerialPort serialPort = null;

        /// <summary>
        /// 静态构造函数，主要用来配置串口
        /// </summary>
        static Cabinet()
        {
            serialPort = MainForm.serialPort;
        }

        public static event Action<string> SendCmd_Event;
        public static event Action<string> GetAsw_Event;

        #region 内部方法
        /// <summary>
        /// 发送字符串查询命令（底层方法）
        /// </summary>
        /// <param name="Addr">药剂柜控制板地址</param>
        /// <param name="Cmd">查询命令</param>
        private static void SendCommand(int Addr, string Cmd)
        {
            var FullCmd = "#~" + Addr.ToString().PadLeft(3, '0') + "~qst~" + Cmd + "~@";
            SendCmd_Event?.Invoke("Send: " + FullCmd);
            serialPort.WriteLine(FullCmd);
        }

        /// <summary>
        /// 根据查询命令试图构建出正确应答字符串（底层方法）
        /// </summary>
        /// <param name="Addr">药剂柜控制板地址</param>
        /// <param name="Cmd">查询命令</param>
        /// <returns>预期应答字符串</returns>
        private static string BuildAnswer(int Addr, string Cmd)
        {
            var FullAsw = "#~" + Addr.ToString().PadLeft(3, '0') + "~asw~" + Cmd + "~@";
            return FullAsw;
        }

        /// <summary>
        /// 判断查询状态命令的返回字符串格式是否合法（底层方法）
        /// </summary>
        /// <param name="Str">查询状态命令的返回字符串</param>
        /// <returns>布尔值，代表格式是否合法</returns>
        private static bool StrIsLegal(string Str)
        {
            Regex Rg = new Regex(@"^#~(\d{3})(~asw~t)(-?\d+)(\.\d+)?(~h)(-?\d+)(\.\d+)?(~s)([0-1]{8})~@$");
            if (Rg.IsMatch(Str))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 根据合法的查询状态应答字符串构建出药剂柜状态对象（底层方法）
        /// </summary>
        /// <param name="Str">合法的查询状态命令的返回字符串</param>
        /// <returns>药剂柜状态对象</returns>
        private static CabinetStatus GetCabinetStatus(string Str)
        {
            Regex RgTem = new Regex(@"~t(-?\d+)(\.\d+)?");
            Regex RgHum = new Regex(@"~h(-?\d+)(\.\d+)?");
            Regex RgStatus = new Regex(@"(~s)([0-1]{8})");

            var StrTem = RgTem.Match(Str).Value;
            var StrHum = RgHum.Match(Str).Value;
            var StrStatus = RgStatus.Match(Str).Value;
            StrTem = StrTem.Substring(2, StrTem.Length - 2);
            StrHum = StrHum.Substring(2, StrHum.Length - 2);
            StrStatus = StrStatus.Substring(2, StrStatus.Length - 2);

            CabinetStatus Cs = new CabinetStatus();
            double TmpDb = 0.0;
            double.TryParse(StrTem, out TmpDb);
            Cs.Tem = TmpDb;
            double.TryParse(StrHum, out TmpDb);
            Cs.Hum = TmpDb;

            Cs.FanOn = StrStatus.Substring(7, 1) == "1" ? true : false;
            Cs.LightOn = StrStatus.Substring(6, 1) == "1" ? true : false;
            Cs.LockIsLock = StrStatus.Substring(5, 1) == "0" ? true : false;
            Cs.DoorIsClose = StrStatus.Substring(4, 1) == "0" ? true : false;
            Cs.RunLigthStatus = StrStatus.Substring(3, 1) == "0" ? true : false;
            Cs.SignalLightStatus = StrStatus.Substring(2, 1) == "0" ? true : false;
            Cs.FilterLifeLightStatus = StrStatus.Substring(1, 1) == "0" ? true : false;
            Cs.AbnormalLightStatus = StrStatus.Substring(0, 1) == "0" ? true : false;

            return Cs;
        }

        /// <summary>
        /// 完成一次普通行动（底层方法）
        /// </summary>
        /// <param name="Cmd">查询字符串</param>
        /// <returns>结果，ok代表行动成功，非ok代表出现异常</returns>
        private static string Action(string Cmd)
        {
            try
            {
                //这里加上锁，确保命令按顺序工作
                lock (serialPort)
                {
                    SendCommand(0, Cmd);
                    var RtStr = serialPort.ReadLine();
                    GetAsw_Event?.Invoke("Get: " + RtStr);
                    if (RtStr == BuildAnswer(0, Cmd))
                    {
                        return "ok";
                    }
                    else
                    {
                        return "药剂柜应答有误";
                    }
                }
            }
            catch (Exception e)
            {
                return e.Message;
            }
        }
        #endregion

        #region 外部暴露功能
        /// <summary>
        /// 与药剂柜握手
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string HandShake()
        {
            var ResStr = Action("handshake");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    return "ok";
                }
                else
                {
                    return "尝试握手后无法获取药剂柜状态";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 打开风机
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string FanOpen()
        {
            var ResStr = Action("fan1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.FanOn)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "开启风机失败";
                    }
                }
                else
                {
                    return "已尝试开启风机，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 关闭风机
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string FanClose()
        {
            var ResStr = Action("fan0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.FanOn == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "关闭风机失败";
                    }
                }
                else
                {
                    return "已尝试关闭风机，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 打开柜内照明灯
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string LightOpen()
        {
            var ResStr = Action("light1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.LightOn)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "照明灯打开失败";
                    }
                }
                else
                {
                    return "已尝试开启柜内照明灯，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 关闭柜内照明灯
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string LightClose()
        {
            var ResStr = Action("light0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.LightOn == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "照明灯关闭失败";
                    }
                }
                else
                {
                    return "已尝试关闭柜内照明灯，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 门锁打开
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string LockOpen()
        {
            var ResStr = Action("lock1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.LockIsLock == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "电锁解锁失败";
                    }
                }
                else
                {
                    return "已尝试解锁药剂柜电锁，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 门锁关闭
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string LockClose()
        {
            var ResStr = Action("lock0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.LockIsLock)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "电锁上锁失败";
                    }
                }
                else
                {
                    return "已尝试锁药剂柜电锁，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 滤芯寿命预警设置
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string FilterLifeSet()
        {
            var ResStr = Action("filterlife1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.FilterLifeLightStatus == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "滤芯警报设置失败";
                    }
                }
                else
                {
                    return "已尝试设置滤芯警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 滤芯寿命预警清除
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string FilterLifeClear()
        {
            var ResStr = Action("filterlife0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.FilterLifeLightStatus)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "滤芯警报取消失败";
                    }
                }
                else
                {
                    return "已尝试取消滤芯警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 网络异常设置
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string NetworkSet()
        {
            var ResStr = Action("network1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.SignalLightStatus == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "网络通信警报设置失败";
                    }
                }
                else
                {
                    return "已尝试设置网络通信警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 网络异常清除
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string NetworkClear()
        {
            var ResStr = Action("network0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.SignalLightStatus)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "网络通信警报取消失败";
                    }
                }
                else
                {
                    return "已尝试取消网络通信警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 柜门异常设置
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string DoorSet()
        {
            var ResStr = Action("door1");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.AbnormalLightStatus == false)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "柜门警报设置失败";
                    }
                }
                else
                {
                    return "已尝试设置柜门警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 柜门异常清除
        /// </summary>
        /// <returns>成功返回ok，否则返回异常信息</returns>
        public static string DoorClear()
        {
            var ResStr = Action("door0");
            if (ResStr == "ok")
            {
                var Status = GetStatus();
                if (Status != null)
                {
                    if (Status.AbnormalLightStatus)
                    {
                        return "ok";
                    }
                    else
                    {
                        return "柜门警报取消失败";
                    }
                }
                else
                {
                    return "已尝试取消柜门警报，但结果无法确认";
                }
            }
            else
            {
                return ResStr;
            }
        }

        /// <summary>
        /// 查询药剂柜状态
        /// </summary>
        /// <returns>药剂柜状态对象，查询失败返回null</returns>
        public static CabinetStatus GetStatus()
        {
            try
            {
                //这里加上同步锁，确保命令按顺序工作
                lock (serialPort)
                {
                    SendCommand(0, "status");
                    var RtStr = serialPort.ReadLine();
                    GetAsw_Event?.Invoke("Get: " + RtStr);
                    if (StrIsLegal(RtStr))
                    {
                        return GetCabinetStatus(RtStr);
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            catch
            {
                return null;
            }
        }
        #endregion
    }
}
